const defAttr = () => ({
  program: null,
  data: {}, //在同一个程序集对象中, 所有Unifrom变量值都是相同的,除非在更新前重新更改,否则会后覆盖前
  // 'u_Color': {
  //     value: [1, 1, 1, 1],
  //     type: 'unifroms4fv',
  //     location: null,
  //     needUpdate: true,
  //     cRend : false, //持续渲染
  // }
  mode: [
    "POINTS",
    "TRIANGLES",
    "TRIANGLE_STRIP",
    "TRIANGLE_FAN",
    "LINES",
    "LINE_STRIP",
    "LINE_LOOP",
  ],
  maps: {},
  // 'u_Sampler': {
  //     image: image,
  //     texture : textureBuffer,

  //     WRAP_W: gl.CLAMP_TO_EDGE,
  //     WRAP_H: gl.CLAMP_TO_EDGE,
  //     MIN_FILTER: gl.LINEAR,
  //     MAG_FILTER: gl.LINEAR,//线性, 无锯齿

  //     format: gl.RGB,
  //     flipY: 1,
  //     location: null,
  //     needUpdate: true,
  // }
});

//材质对象
export default class Mat {
  constructor(attr) {
    Object.assign(this, defAttr(), attr);
  }

  init(gl) {
    const { data, maps } = this;

    // Object.entries(data).forEach(([key, val], index) => {
    //     val.needUpdate = true;
    //     //继续加上是否需要变换
    //     //用在判断 uniform 变量是否经过了外界的变换
    //     //目前应该是一直是 True
    //     //只有 u_ModelM4 会变成 False
    //     //因为在 Obj3D.allTransform() 中进行了变换
    // });
    Object.entries(maps).forEach(([key, val], index) => {
      if (!val.texture) {
        val.texture = gl.createTexture();
        //感觉这个地方还是需要needUpdate
      }
      this._updateMap(gl, index, val);
    });
  }

  update(gl, uniforms) {
    this._updateData(gl, uniforms);
    this._updateMaps(gl, uniforms);
  }

  _updateData(gl, uniforms) {
    const { data } = this;
    Object.entries(data).forEach(([key, val], index) => {
      const { value, type } = val;
      const location = uniforms.get(key);

      if (type.indexOf("Matrix") == -1) {
        gl[type](location, value);
      } else {
        gl[type](location, false, value);
      }
    });
  }

  _updateMaps(gl, uniforms) {
    const { maps } = this;
    Object.entries(maps).forEach(([key, value], index) => {
      const location = uniforms.get(key);
      if (location) {
        this._updateMap(gl, index, value);
        gl.bindTexture(gl.TEXTURE_2D, value.texture);
        gl.uniform1i(location, index); //gl.TEXTURE0激活的是0
      }
    });
  }

  _updateMap(gl, index, value) {
    const {
      image,
      texture,
      WRAP_H,
      WRAP_W,
      MIN_FILTER,
      MAG_FILTER,
      format = gl.RGB,
      flipY = 1,
    } = value;

    if (!texture) {
      val.texture = gl.createTexture();
    }

    //是否反转Y轴
    flipY && gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
    // 激活纹理单元
    gl.activeTexture(gl[`TEXTURE${index}`]);
    gl.bindTexture(gl.TEXTURE_2D, value.texture);
    image &&
      gl.texImage2D(gl.TEXTURE_2D, 0, format, format, gl.UNSIGNED_BYTE, image);

    //设置非二次幂图片(非二次幂图片只有在边缘加紧时才可以显示)
    WRAP_H &&
      gl.texParameteri(
        gl.TEXTURE_2D, //二维纹理
        gl.TEXTURE_WRAP_T, //纹理容器在t方向的尺寸
        gl.CLAMP_TO_EDGE //边缘加紧的意思
      );
    WRAP_W &&
      gl.texParameteri(
        gl.TEXTURE_2D, //二维纹理
        gl.TEXTURE_WRAP_S, //纹理容器在s方向的尺寸
        gl.CLAMP_TO_EDGE //边缘加紧的意思
      );

    MAG_FILTER &&
      gl.texParameteri(
        gl.TEXTURE_2D, //二维纹理
        gl.TEXTURE_MAG_FILTER, //纹理缩小滤波器(当图片源比显示框大的时候进行等比缩小)
        MAG_FILTER //线性
      );

    if (!MIN_FILTER || MIN_FILTER > 9729) {
      gl.generateMipmap(gl.TEXTURE_2D);
    }

    MIN_FILTER &&
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, MIN_FILTER);
    // gl.bindTexture(gl.TEXTURE_2D, null);
  }

  setData(key, value) {
    const { data } = this;
    if (!data[key]) {
      return;
    }
    // data[key].needUpdate = true;
    Object.assign(data[key], value);
  }

  setMap(key, value) {
    const { maps } = this;
    let map = maps[key];
    if (!map) return;
    map.needUpdate = true;
    Object.assign(map, value);
  }

  //旧的
  addMap(gl, _key, _value) {
    _value.needUpdate = true;
    if (!_value.texture) {
      _value.texture = gl.createTexture();
    }
    Object.assign(this.maps, { _key: _value });
  }

  addMapNew(gl, data) {
    Object.entries(data).forEach(([key, val], index) => {
      val.needUpdate = true;
      if (!val.texture) {
        val.texture = gl.createTexture();
      }
      Object.assign(this.maps, data);
    });
  }

  clone() {
    const { program, mode, data, maps } = this;

    let curData = {};
    Object.entries(data).forEach(([key, val], index) => {
      curData[key] = {
        type: val.type.slice(),
      };
      if (val.type.lastIndexOf("v") == val.type.length - 1) {
        curData[key].value = val.value.concat();
      } else {
        curData[key].value = val.value;
      }
    });

    let curMap = {};
    Object.entries(maps).forEach(([key, val], index) => {
      curMap[key] = {
        image: val.image,
        WRAP_W: val.WRAP_W,
        WRAP_H: val.WRAP_H,
        MIN_FILTER: val.MIN_FILTER,
        MAG_FILTER: val.MAG_FILTER,
        format: val.format,
        flipY: val.flipY,
      };
    });

    return new Mat({
      program: program,
      mode: mode.concat(),
      data: curData,
      maps: curMap,
    });
  }
}
